home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
mxcode
/
soundx
/
sound.c
< prev
next >
Wrap
Text File
|
1993-06-27
|
17KB
|
902 lines
/* Copyright 1993 by Peter Sprenger Pete@amber.dinoco.de
* 5014 Kerpen 3
* Germany
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The author Peter Sprenger
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <io.h>
#include <fcntl.h>
#include <alloc.h>
#include <sys\stat.h>
#include "mydef.h"
#include "sound.h"
#include "timerx.h"
#include "dmalib.h"
static WORD ioaddr[6]={0x220,0x240,0x210,0x230,0x250,0x260};
static WORD FM_off[9]={0,0x100,0x200,0x800,0x900,0xa00,0x1000,0x1100,0x1200};
static BYTE FM_fnr[12]={0x57,0x6b,0x81,0x98,0xb0,0xca,0xe5,0x02,0x20,0x41,0x63,0x87};
static BYTE FM_key_or[12]={1,1,1,1,1,1,1,2,2,2,2,2};
static BYTE intrx[5]={7,5,2,3,10};
static BYTE FM_key[9],FM_vol[9];
WORD io_addr,intnr,dma_ch,card_id,fm_addr,fm_left,fm_right,fm_both;
static WORD mue3,mue23,dsp_vers,wh_card,rythm,rx,ry,midi_buflen;
static WORD voccnt,cnt;
static BYTE DSP_intr_mode,DSP_high_mode,midi_mode,far *midi_recv;
volatile BYTE voc_mode,tst_cnt,dma_sb_busy;
static BYTE huge *vocptr,huge *vocrem,voc_ext,voc_pmode;
static DWORD voc_blklen;
static void far interrupt (*orgint)();
/* --------------- FM Stuff ------------ */
void FM_Write(WORD data)
{
asm mov dx,fm_addr;
asm mov ax,data;
asm xchg al,ah;
asm out dx,al;
asm mov cx,mue3;
loop1:
asm loop loop1;
asm inc dx;
asm mov al,ah;
asm out dx,al;
mdelay(mue23);
}
void FM_Reset()
{
FM_SetChan(both);
FM_Write(0x0120);
FM_Write(0x0800);
FM_Write(0xbdc0);
}
BYTE FM_Status()
{
asm mov dx,fm_addr;
asm in al,dx;
return(_AL);
}
static int FM_Detect()
{
int i;
FM_Write(0x0100); /* init Test register */
FM_Write(0x0460); /* reset both timer */
FM_Write(0x0480); /* enable interrupts */
if(FM_Status() & 0xe0) return(FALSE);
FM_Write(0x02ff); /* write ffh to timer 1 */
FM_Write(0x0421); /* start timer 1 */
if(fm_addr==0x388) msdelay(21); /* wait 21000 mcs */
else mdelay(mcalc(80)); /* wait at least 80 microsec */
if((FM_Status() & 0xe0)!=0xc0) return(FALSE);
FM_Write(0x0460); /* reset both timer */
FM_Write(0x0480); /* enable interrupts */
return(TRUE);
}
void FM_SetChan(fm_chan channel)
{
if(channel!=sbpro) return;
switch(channel)
{
case both:
fm_addr=fm_both;
break;
case left:
fm_addr=fm_left;
break;
case right:
fm_addr=fm_right;
}
}
void FM_SetVoice(BYTE voice,BYTE *ins)
{
BYTE *insptr;
WORD data;
int i;
insptr=ins;
FM_vol[voice]=insptr[3];
data=0x2000+FM_off[voice];
for(i=0;i<5;i++)
{
data=data&0xff00| *insptr++;
FM_Write(data);
data+=0x300;
data=data&0xff00| *insptr++;
FM_Write(data);
data=data+(0x2000-0x300);
if(i==3) data+=4000;
}
data=0xc000+(voice<<8);
data=data&0xff00| *insptr;
FM_Write(data);
}
void FM_SetNote(BYTE voice,BYTE note)
{
BYTE blk,notex;
WORD data;
notex=note-24;
blk=1;
while(notex>=12)
{
notex-=12;
blk++;
}
data=0xa000+(voice<<8)|FM_fnr[notex];
FM_key[voice]=FM_key_or[notex]|(blk<<2);
FM_Write(data);
}
void FM_SetVol(BYTE voice,BYTE vol)
{
FM_Write(0x4320+FM_off[voice]-(((BYTE)vol&0x7f)>>2)|FM_vol[voice]);
}
void FM_RythmMode(BYTE bool)
{
WORD data;
if(bool) data=0xbde0;
else data=0xbdc0;
rythm=data;
FM_Write(data);
}
void FM_RythmOn(BYTE inst)
{
rythm|=inst;
FM_Write(rythm);
}
void FM_RythmOff(BYTE inst)
{
rythm&=(~inst);
FM_Write(rythm);
}
void FM_KeyOn(BYTE voice)
{
WORD data;
data=0xb000+(voice<<8)|FM_key[voice]|0x20;
FM_Write(data);
}
void FM_KeyOff(BYTE voice)
{
WORD data;
data=0xb000+(voice<<8)|FM_key[voice];
FM_Write(data);
}
/* --------------- Mixer Stuff ------------ */
void MIX_Reset()
{
asm mov dx,io_addr
asm add dx,MIX_ADR_OFF
asm mov al,0
asm out dx,al
asm inc dx
asm out dx,al
}
void MIX_SetInput(BYTE opt)
{
asm mov dx,io_addr;
asm add dx,MIX_ADR_OFF;
asm mov al,MIX_INPUT;
asm out dx,al;
asm inc dx;
asm mov al,opt;
asm out dx,al;
}
void MIX_SetOutput(BYTE opt)
{
asm mov dx,io_addr;
asm add dx,MIX_ADR_OFF;
asm mov al,MIX_OUTPUT;
asm out dx,al;
asm inc dx;
asm mov al,opt;
asm out dx,al;
}
void MIX_SetVolume(BYTE reg,BYTE left,BYTE right)
{
asm mov dx,io_addr
asm add dx,MIX_ADR_OFF
asm mov al,reg
asm out dx,al
asm inc dx
asm mov al,left
asm mov cl,4
asm shl al,cl
asm or al,right
asm out dx,al
}
void MIX_GetVolume(BYTE reg,BYTE *left,BYTE *right)
{
asm mov dx,io_addr
asm add dx,MIX_ADR_OFF
asm mov al,reg
asm out dx,al
asm inc dx
asm in al,dx
asm mov ah,al
asm les bx,right
asm and al,0xf
asm mov es:[bx],al
asm mov al,ah
asm les bx,left
asm mov cl,4
asm shr al,cl
asm mov es:[bx],al
}
/* --------------- Midi Stuff ------------ */
void MIDI_Write(BYTE data)
{
DSP_Write(DSP_MIDI_WRITE);
DSP_Write(data);
}
void MIDI_WriteBuf(BYTE *data,int length)
{
int i;
for(i=0;i<length;i++) MIDI_Write(data[i]);
}
static void far interrupt midi_int()
{
asm mov dx,io_addr; /* read midi code from DSP */
asm add dx,DSP_READ;
asm in al,dx;
asm mov si,rx; /* write code into buffer */
asm inc si;
asm cmp si,midi_buflen; /* make turnaround at buffer limit */
asm jnz no_turn
asm mov si,0
no_turn:
asm mov rx,si;
asm les bx,midi_recv;
asm mov es:[bx][si],al
asm mov dx,io_addr;
asm add dx,DSP_RSTATUS;
asm in al,dx; /* Ack DSP interrupt */
asm mov al,0x20;
asm out 0x20,al; /* set EOI to master */
asm mov bx,intnr
asm cmp bx,7
asm jbe end
asm out 0xa0,al; /* set EOI to slave */
end:
}
WORD MIDI_ByteAvail()
{
if(ry<rx) return(midi_buflen-rx+ry);
else return(ry-rx);
}
BYTE MIDI_GetByte()
{
if(++ry==midi_buflen) ry=0;
return(midi_recv[ry]);
}
void MIDI_ReadBuf(WORD count,BYTE *buffer)
{
int i;
for(i=0;i<count;i++)
{
if(++ry==midi_buflen) ry=0;
buffer[i]=midi_recv[ry];
}
/* not the fastest! this routine has to be improved in the future */
}
int MIDI_Init(BYTE mode,WORD buflen)
{
midi_mode=mode;
if(mode==DSP_MIDI_UART && dsp_vers<0x2000) return(FALSE);
midi_recv=malloc(buflen);
if(!midi_recv) return(FALSE);
midi_buflen=buflen;
rx=ry=0;
DSP_Write(mode);
return(TRUE);
}
void MIDI_Remove()
{
if(midi_mode==DSP_MIDI_READI) DSP_Write(DSP_MIDI_READI);
else DSP_Reset();
if(midi_recv) free(midi_recv);
}
/* --------------- voc Stuff ------------ */
int VocPlay(char far *data)
{
vocptr=data;
if(strncmp(vocptr,"Creative Voice File\x1a",20) || *((WORD *)vocptr+11)!=(~*((WORD *)vocptr+12)+0x1234))
return(FALSE);
vocptr+=*((WORD *)vocptr+10);
voc_mode=TRUE;
voc_ext=FALSE;
voccnt=0;
VocHandle();
return(TRUE);
}
void VocStop()
{
voc_mode=FALSE;
if(dma_sb_busy) DSP_Write(DSP_HALT_DMA);
}
static void VocHandle()
{
BYTE tmp;
while(*vocptr)
{
voc_blklen=((DWORD)(*(vocptr+3))<<16)+ *((WORD *)(vocptr+1))+4;
switch(*vocptr)
{
case 1: if(!voc_ext)
{
DSP_Write(DSP_SAMPLE_RATE);
DSP_Write(*(vocptr+4));
voc_pmode=*(vocptr+5);
}
else
voc_ext=FALSE;
Play((char far *)vocptr+6,voc_pmode,voc_blklen-6);
vocptr+=voc_blklen;
return;
case 2: Play((char far *)vocptr+4,voc_pmode,voc_blklen-4);
vocptr+=voc_blklen;
return;
case 3: DSP_Write(DSP_SAMPLE_RATE);
DSP_Write(*(vocptr+6));
DSP_Write(DSP_SILENCE);
DSP_Write(*(vocptr+4));
DSP_Write(*(vocptr+5));
vocptr+=7;
return;
case 6: vocrem=vocptr+6;
voccnt=*((WORD *)(vocptr+4));
vocptr+=6;
break;
case 7: if(voccnt) vocptr=vocrem;
if(voccnt!=0xffff) voccnt--;
break;
case 8: DSP_Write(DSP_SAMPLE_RATE);
DSP_Write(*(vocptr+5));
if(*(vocptr+7)) tmp=MIX_STEREO;
else tmp=MIX_MONO;
MIX_SetOutput(tmp);
voc_pmode=*(vocptr+6);
voc_ext=TRUE;
vocptr+=8;
break;
}
}
voc_mode=FALSE;
}
/* --------------- DSP Stuff ------------ */
int DSP_Reset()
{
int i;
asm mov dx,io_addr;
asm add dx,DSP_RESET;
asm mov al,1
asm out dx,al;
mcalc(mue3);
asm mov dx,io_addr;
asm add dx,DSP_RESET;
asm mov al,0
asm out dx,al;
for(i=0;i<50;i++)
{
mcalc(mue3);
if(DSP_Read()==0xaa) return(TRUE);
}
return(FALSE);
}
BYTE DSP_Read()
{
asm mov dx,io_addr;
asm add dx,DSP_RSTATUS;
loop:
asm in al,dx;
asm test al,0x80;
asm jz loop
asm mov dx,io_addr;
asm add dx,DSP_READ;
asm in al,dx;
return(_AL);
}
void DSP_Write(BYTE output)
{
asm mov dx,io_addr;
asm add dx,DSP_WSTATUS;
loop:
asm in al,dx;
asm test al,0x80;
asm jnz loop
asm mov dx,io_addr;
asm add dx,DSP_WRITE;
asm mov al,output
asm out dx,al;
}
int get_sb_env()
{
char *str;
int ret;
str=getenv("BLASTER");
if(!str) return(FALSE);
ret=sscanf(str,"A%x I%d D%d T%d",&io_addr,&intnr,&dma_ch,&card_id);
if(ret!=4 || io_addr<0x210 || io_addr>0x260 || dma_ch!=1 || intnr<2 || intnr>10)
return(FALSE);
return(TRUE);
}
void SetRate(DWORD rate)
{
DWORD val;
if(rate<4000) return;
val=256-1000000/rate;
DSP_Write(DSP_SAMPLE_RATE);
DSP_Write((BYTE)val);
}
void SetHighRate(DWORD rate)
{
WORD val;
if(rate<4000) return;
val=65536-(WORD)(256000000/rate);
DSP_Write(DSP_SAMPLE_RATE);
DSP_Write((BYTE)(val>>8));
}
WORD DSP_GetVersion()
{
DSP_Write(DSP_GET_VERS);
return((WORD)DSP_Read()*256+DSP_Read());
}
int Play(char far *data,playmode mode,DWORD length)
{
return(PlayXMS(far2long(data),mode,length));
}
int PlayXMS(DWORD data,playmode mode,DWORD length)
{
WORD len;
BYTE dsp_mode;
if(dma_sb_busy)
{
DSP_Write(DSP_HALT_DMA); /* halt dma */
dma_sb_busy=FALSE;
}
len=dma_set(data,length,dma_ch,DMA_OUT|DMA_SINGLE|DMA_AUTO)-1; /* set dma */
DSP_high_mode=0;
switch(mode)
{
case bit8:
dsp_mode=DSP_DMA_8BIT;
DSP_intr_mode=DSP_DMA_8BIT;
break;
case bit4:
dsp_mode=DSP_DMA_4BIT_REF;
DSP_intr_mode=DSP_DMA_4BIT;
break;
case bit26:
dsp_mode=DSP_DMA_26BIT_REF;
DSP_intr_mode=DSP_DMA_26BIT;
break;
case bit2:
dsp_mode=DSP_DMA_2BIT_REF;
DSP_intr_mode=DSP_DMA_2BIT;
break;
case high:
dsp_mode=DSP_BLOCK_SIZE;
DSP_intr_mode=DSP_BLOCK_SIZE;
DSP_high_mode=DSP_DMA_HIGHSPEED;
}
dma_sb_busy=TRUE;
DSP_Write(dsp_mode);
DSP_Write((BYTE)len); /* write length to DSP */
DSP_Write((BYTE)(len>>8));
if(DSP_high_mode) DSP_Write(DSP_DMA_HIGHSPEED);
return(TRUE);
}
int Sample(char far *data,playmode mode,DWORD length)
{
WORD len;
BYTE dsp_mode;
if(dma_sb_busy)
{
DSP_Write(DSP_HALT_DMA); /* halt dma */
dma_sb_busy=FALSE;
}
len=dma_set(far2long(data),length,dma_ch,DMA_IN|DMA_SINGLE|DMA_AUTO)-1; /* set dma */
DSP_high_mode=0;
switch(mode)
{
case bit8:
dsp_mode=DSP_DMA_ADC;
DSP_intr_mode=DSP_DMA_ADC;
break;
case high:
dsp_mode=DSP_BLOCK_SIZE;
DSP_intr_mode=DSP_BLOCK_SIZE;
DSP_high_mode=DSP_DMA_ADC_HIGHSPEED;
}
dma_sb_busy=TRUE;
DSP_Write(dsp_mode);
DSP_Write((BYTE)len); /* write length to DSP */
DSP_Write((BYTE)(len>>8));
if(DSP_high_mode) DSP_Write(DSP_DMA_ADC_HIGHSPEED);
return(TRUE);
}
static void far interrupt sb_int()
{
WORD length;
asm mov dx,io_addr;
asm add dx,DSP_RSTATUS;
asm in al,dx; /* Ack DSP interrupt */
if(dma_len(dma_ch)) /* if bytes left reprogram DSP */
{
length=dma_next(dma_ch)-1; /* check for another dma block */
DSP_Write(DSP_intr_mode); /* set DSP mode */
DSP_Write((BYTE)length);
DSP_Write((BYTE)(length>>8));
if(DSP_high_mode) DSP_Write(DSP_high_mode);
}
else
{
dma_sb_busy=FALSE;
if(voc_mode) VocHandle();
}
asm mov al,0x20;
asm out 0x20,al; /* set EOI */
asm mov bx,intnr
asm cmp bx,7
asm jbe end
asm out 0xa0,al; /* set EOI */
end:
}
/* --------------- Misc. Stuff ------------ */
int CardCheck()
{
int ret=0;
if(FM_Detect()) ret|=FM_DETECT;
if(DSP_Reset()) ret|=DSP_DETECT;
return(ret);
}
static void far interrupt testn_int()
{
tst_cnt++;
asm mov dx,io_addr;
asm add dx,DSP_RSTATUS;
asm in al,dx; /* Ack DSP interrupt */
asm mov al,0x20;
asm out 0x20,al; /* set EOI */
asm mov bx,intnr
asm cmp bx,7
asm jbe end
asm out 0xa0,al; /* set EOI */
end:
}
static BYTE scan_dma()
{
BYTE dma1,dma2,dma1r,dma2r,cnt;
DSP_Write(DSP_SPKR_OFF);
SetRate(22000);
DSP_Write(DSP_DMA_8BIT);
DSP_Write(10);
asm cli
asm in al,8
asm and al,0xe0
asm mov dma1,al
asm in al,0xd0
asm and al,0xf0
asm mov dma2,al
DSP_Write(0);
asm mov cx,60000
loop1:
asm in al,8
asm and al,0xe0
asm mov dma1r,al
asm cmp al,dma1
asm jnz req
asm in al,0xd0
asm and al,0xf0
asm mov dma2r,al
asm cmp al,dma2
asm jnz req
asm loop loop1
req:
asm sti
DSP_Reset(); /* cause our DSP it's a little bit confused */
if(dma1!=dma1r)
{
cnt=0;
dma1r=dma1r&(~dma1);
while(dma1r>>=1) cnt++;
return(cnt-4);
}
if(dma2!=dma2r)
{
cnt=0;
dma2r=dma2r&(~dma2);
while(dma2r>>=1) cnt++;
return(cnt-4);
}
return(0xff); /* no dma request occured ???? */
}
static int test_int()
{
int i;
BYTE int1,int2;
tst_cnt=0;
orgint=getvect(int2vect(intnr));
asm in al,0x21; /* save org master intr settings */
asm mov int1,al;
asm in al,0xa1; /* save org slave intr settings */
asm mov int2,al;
asm mov al,0xfe;
asm cli;
asm out 0x21,al; /* disable ALL intr */
asm mov al,0xff
asm out 0xa1,al;
asm sti;
enable_int(intnr);
setvect(int2vect(intnr),testn_int);
DSP_Write(DSP_INVOKE_INTR); /* still magic -- make DSP interrupt? */
for(i=0;i<30000;i++) if(tst_cnt) break;
asm cli;
asm mov al,int1;
asm out 0x21,al; /* restore org master intr */
asm mov al,int2; /* restore org slave intr */
asm out 0xa1,al;
asm sti;
setvect(int2vect(intnr),orgint);
if(i==30000) return(FALSE);
else return(TRUE);
}
static int scan_int()
{
int i;
if(test_int()) return(intnr);
for(i=0;i<5;i++)
{
intnr=intrx[i];
if(test_int()) return(i);
}
return(0);
}
static cardtype CheckHard()
{
int ret,ret2,ret3;
ret=DSP_Reset();
if(ret)
{
if(!scan_int()) return(none);
fm_addr=io_addr+FM_BOTH_OFF;
if(!FM_Detect()) return(none); /* no fm? -> damaged! */
fm_both=fm_addr;
fm_addr=io_addr+FM_RIGHT_OFF;
fm_right=fm_addr;
ret3=FM_Detect();
fm_addr=fm_both;
if(ret3)
{
wh_card=sbpro;
fm_left=io_addr+FM_LEFT_OFF;
}
else wh_card=sb20;
return(wh_card);
}
return(nodsp);
}
cardtype WhichCard()
{
cardtype cret;
int i;
if(get_sb_env()) cret=CheckHard();
if(cret!=nodsp) return(cret);
intnr=7;
for(i=0;i<6;i++)
{
io_addr=ioaddr[i];
cret=CheckHard();
if(cret!=nodsp) return(cret);
}
fm_addr=0x388;
if(FM_Detect())
{
fm_both=fm_addr;
wh_card=adlib;
return(adlib);
}
return(none);
}
int SB_Setup()
{
int ret,ret2;
InitT2(); /* init Timer 2 */
measure(); /* time loop factor */
mue3=mcalc(3); /* calc val for 3 micro sec delay */
mue23=mcalc(23); /* calc val for 23 micro sec delay */
dma_sb_busy=FALSE;
voc_mode=FALSE;
WhichCard();
if(wh_card==none) return(FALSE);
if(wh_card==sb20 || wh_card==sbpro)
{
dma_ch=scan_dma();
if(dma_ch==0xff) return(FALSE);
dsp_vers=DSP_GetVersion();
DSP_Write(DSP_SPKR_ON);
}
return(TRUE);
}
void SB_SetVect(vect which)
{
orgint=getvect(int2vect(intnr));
if(which==midi) setvect(int2vect(intnr),midi_int);
setvect(int2vect(intnr),sb_int); /* set vector to our routine */
enable_int(intnr); /* enable sb interrupt */
}
void SB_RemoveVect()
{
disable_int(intnr); /* disable sb interrupt */
setvect(int2vect(intnr),orgint); /* restore org intr vector */
}